package main

import "fmt"

//map 是引用类型

func MapTest() {
	m1 := make(map[string]string, 5)
	m2 := make(map[string]string)
	m3 := map[int]string{}
	m4 := map[int]int{11: 1, 22: 2, 33: 3} //初始化 并赋值
	fmt.Println(m1, len(m1))               //未初始化的 map 的值是 nil
	fmt.Println(m2, len(m2))
	fmt.Println(m3, len(m3))
	fmt.Println(m4, len(m4)) // 取出值以及map长度
	fmt.Println(m4[22])      //根据key获取value

	//m3 m4的初始化方式等价   空的map可以赋值设置元素
	m3[11] = "AAA"
	m3[22] = "BBB"
	m3[33] = "CCC"
	fmt.Println(m3, len(m3), m3[33])

	//m5 m6创建方式等价  都创建一个空的map  m5 m6没有任何元素
	m5 := make(map[string]int)
	m6 := map[string]int{} //创建了初始化了一个空的map，这个时候m6没有任何元素
	//m7 := map[string]int  //错误的定义方式

	fmt.Println(m1 == nil, m2 == nil, m3 == nil, m5 == nil, m6 == nil)
	//false false false false false
	//空的map不等价于nil(map的零值状态)

	m5["A"] = 1
	m6["B"] = 2
	//m7["C"] = 3
}

//map 遍历 与 nil
func MapTest2() {
	ages1 := map[string]int{
		"python": 3,
		"C":      2,
		"C++":    1,
		"GoLang": 4, // 此处最后一个逗号需要加上
	}
	ages1["rocket"] = 100
	//遍历
	for name, age := range ages1 {
		fmt.Printf("%s\t%d\n", name, age)
	}

	//声明但未初始化map，此时是map的零值状态（只有一个nil元素）
	var null_map map[string]int
	fmt.Println(null_map, len(null_map), null_map == nil)

	//无法给未初始化的map赋值设置元素
	//null_map["age"] = 100  //报错 panic: assignment to entry in nil map
}

//map增删改查
func MapTest3() {
	personSalary := make(map[string]float32)
	personSalary["C"] = 12000.5
	personSalary["C++"] = 20000.6 //增加元素
	fmt.Println("first:", personSalary)
	personSalary["C++"] = 30000.6  //修改元素
	fmt.Println("after:", personSalary)
	fmt.Println(personSalary["C"])//获取元素

	//删除元素  delete函数没有返回值
	delete(personSalary,"C++")
	fmt.Println("delete:",personSalary)

	//获取一个不存在的  删除一个不存在的
	fmt.Println("获取一个不存在的：",personSalary["Golang"]) // 不会抛错，返回一个0

	delete(personSalary,"GoLang") // 删除一个不存在的也不会报错

	// 查找map中某个元素   根据键值索引某个元素时，也会返回两个值：索引到的值和本次索引是否成功
	if v, ok := personSalary["GoLang"]; ok{ //如果存在 ok的值为 true
		fmt.Println("存在该元素", v)
	}else{
		fmt.Println("不存在该元素",v , ok)
	}


	salary, ok := personSalary["Python"]
	if ok{
		fmt.Println("索引成功，salary=%f", salary)
	}else{
		fmt.Println("索引失败，salary=%f", salary) //索引失败会返回value的零值，这里是int类型，所以是0
	}
}

//map的不可比性
func MapTest4(){
	//map和slice，func一样，不支持 == 操作符，就是不能直接比较。唯一合法的就是和nil作比较，判断该map是不是零值状态。
	//定义一个函数比较两个map的键和值是否完全相等
	m1 := map[string]int{
		"A":1,
		"B":2,
	}
	m2 := map[string]int{
		"A":1,
		"B":2,
	}
	m3 := map[string]int{
		"A":1,
	}
	var status bool
	status = map_equal(m1, m2)
	fmt.Println(status)
	status = map_equal(m2, m3)
	fmt.Println(status)
}


//比较两个map是否相等
func map_equal(map1, map2 map[string]int)bool{
	if len(map1) != len(map2){
		return false
	}
	for k, map1_v := range map1{
		if map2_v, ok := map2[k]; !ok || map2_v != map1_v{
			return false
		}
	}
	return true
}

func main() {
	//MapTest()
	//MapTest2()
	//MapTest3()
	MapTest4()
}
